package jcer.core;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

public class Connection {
	static enum State {
		READ_HEADER, READ_BODY, TASK_EXECUTE, WRITE_RESULT, TASK_COMPLATED
	}

	State state;

	Selector selector;// the main selector which is used to do event driver
	SocketChannel socket;// client socket
	ByteBuffer readBuf;// read buffer
	ByteBuffer writeBuf;// write buffer
	List<Result> resultList = new ArrayList<Result>();// store all result the
														// worker return
	EventDriver driver;// base event driver

	int resultNum;// how many result this conection contains,it is equals to the
					// sub requests contained in client request

	Packet packet;

	public Connection() {
		readBuf = ByteBuffer.allocate(Packet.getHeaderLen());
	}

	/**
	 * call the eventDriver's selector to return
	 */
	public void wakeup() {
		selector.wakeup();
	}

	/**
	 * add result to the list this is thread safe
	 * 
	 * @param result
	 */
	public void addResult(Result result) {
		synchronized (Object.class) {
			resultList.add(result);
			if (resultList.size() == resultNum) {
				Event newEvent = new Event();
				newEvent.type = Event.Type.TASK_COMPLATED;
				newEvent.conn = this;
				driver.addEvent(newEvent);
				// wakeup the base driver
				wakeup();
			}
		}
	}

	/**
	 * read from socket
	 * 
	 * @throws IOException
	 */
	public int read() throws Exception {
		int len = socket.read(readBuf);
		if (len == -1) {
			throw new Exception("Connection Is Close");
		}
		return len;
	}

	/**
	 * write to socket
	 * 
	 * @throws IOException
	 */
	public int write() throws Exception {
		int len = socket.write(writeBuf);
		if (len == -1) {
			throw new Exception("Connection Is Close");
		}
		return len;
	}

	/**
	 * close connection
	 * 
	 * @throws IOException
	 */
	public void close() throws IOException {
		driver.currentConnectionCount--;
		if (socket != null && socket.isConnected()) {
			socket.close();
		}
	}
}
